package main.grammar;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

import view.model.GUINode;

public class GrammarParser {

	public final static String ID = "id";
	public final static String SEQUENCE = "sequence";
	public final static String TOKEN = "token";
	public final static String MINIMUM = "minimum";
	public final static String MAXIMUM = "maximum";
	public final static String NAME = "name";
	public final static String VALUE = "value";
	public final static String EQUIPROBABILITY = "equiprobability";
	public final static String REFERENCE = "reference";
	public final static String PROBABILITY = "probability";
	public final static String ENTITY = "entity";
	public final static String ATTRIBUTE = "attribute";
	public final static String GUI_NODE = "guiNode";
	public final static String X = "x";
	public final static String Y = "y";
	public final static String Z = "z";
	public final static String WIDTH = "width";
	public final static String HEIGHT = "height";
	public final static String COLOR = "color";

	// private final static String GRAMMAR = "grammar";

	private Tokens tokens = new Tokens();

	private String getTokenName(Element tokenNode) {
		Attribute name = tokenNode.getAttribute(NAME);
		return name != null ? name.getValue() : null;
	}

	private String getTokenReference(Element tokenNode) {
		Attribute reference = tokenNode.getAttribute(REFERENCE);
		return reference != null ? reference.getValue() : null;
	}

	private String getTokenValue(Element tokenNode) {
		Attribute value = tokenNode.getAttribute(VALUE);
		return value != null ? value.getValue() : null;
	}

	private boolean isTokenEquiprobability(Element tokenNode) {
		return tokenNode.getChild(EQUIPROBABILITY) != null;
	}

	private boolean isTokenSequence(Element tokenNode) {
		return tokenNode.getChild(SEQUENCE) != null;
	}

	private float getTokenProbability(Element tokenNode) {
		Attribute possibility = tokenNode.getAttribute(PROBABILITY);
		float value = 1;
		if (possibility != null) {
			try {
				value = Float.valueOf(possibility.getValue());
			} catch (NumberFormatException wrongNumberFormat) {
				System.err.println(possibility.getValue() + " is not an float !");
			}
		}
		return value;
	}

	private boolean isTokenMinimumDefined(Element tokenNode) {
		return tokenNode.getAttribute(MINIMUM) != null;
	}

	private boolean isTokenMaximumDefined(Element tokenNode) {
		return tokenNode.getAttribute(MAXIMUM) != null;
	}

	private boolean isTokenProbabilityDefined(Element tokenNode) {
		return tokenNode.getAttribute(PROBABILITY) != null;
	}

	private int getTokenMinimum(Element tokenNode) {
		Attribute minimum = tokenNode.getAttribute(MINIMUM);
		int min = 1;
		if (minimum != null) {
			try {
				min = Integer.valueOf(minimum.getValue());
			} catch (NumberFormatException wrongNumberFormat) {
				System.err.println(minimum.getValue() + " is not an integer !");
			}
		}
		return min;
	}

	private int getTokenMaximum(Element tokenNode) {
		Attribute maximum = tokenNode.getAttribute(MAXIMUM);
		int max = 1;
		if (maximum != null) {
			try {
				max = Integer.valueOf(maximum.getValue());
			} catch (NumberFormatException wrongNumberFormat) {
				System.err.println(maximum.getValue() + " is not an integer !");
			}
		}
		return max;
	}

	private GUINode getTokenGUINode(Element tokenNode) {
		GUINode guiNode = null;
		Element guiNodeInfo = tokenNode.getChild(GUI_NODE);
		if (guiNodeInfo != null) {
			Attribute x = guiNodeInfo.getAttribute(X);
			Attribute y = guiNodeInfo.getAttribute(Y);
			Attribute z = guiNodeInfo.getAttribute(Z);
			Attribute width = guiNodeInfo.getAttribute(WIDTH);
			Attribute height = guiNodeInfo.getAttribute(HEIGHT);
			Attribute color = guiNodeInfo.getAttribute(COLOR);
			try {
				guiNode = new GUINode(x.getIntValue(), y.getIntValue(), z.getIntValue(), width.getIntValue(), height.getIntValue(), color.getValue());
			} catch (DataConversionException myDataConversionException) {
				myDataConversionException.printStackTrace();
			}
		}
		return guiNode;
	}

	@SuppressWarnings("unchecked")
	private Token parseToken(Element tokenNode) {
		Token token = new Token();

		String name = getTokenName(tokenNode);
		String reference = getTokenReference(tokenNode);
		String value = getTokenValue(tokenNode);
		float probability = getTokenProbability(tokenNode);
		int minimum = getTokenMinimum(tokenNode);
		int maximum = getTokenMaximum(tokenNode);
		boolean equiprobability = isTokenEquiprobability(tokenNode);
		boolean sequence = isTokenSequence(tokenNode);
		GUINode guiNode = getTokenGUINode(tokenNode);
		
		
		token.setName(name);
		token.setValue(value);
		token.setProbability(probability);
		token.setMinimum(minimum);
		token.setMaximum(maximum);
		token.setEquiprobability(equiprobability);
		token.setSequence(sequence);
		token.setGuiNode(guiNode);

		List<Element> tokenNodes = tokenNode.getChildren(TOKEN);
		if (tokenNodes != null) {
			for (Element tokenNodeNode : tokenNodes) {
				token.addToken(parseToken(tokenNodeNode));
			}
		}

		token.distribute();

		if (name != null) {
			tokens.addReference(token);
		}

		if (reference != null) {
			token = tokens.getReference(reference).clone();
			if (isTokenMinimumDefined(tokenNode)) {
				token.setMinimum(minimum);
			}
			if (isTokenMaximumDefined(tokenNode)) {
				token.setMaximum(maximum);
			}
			if (isTokenProbabilityDefined(tokenNode)) {
				token.setProbability(probability);
			}
		}

		return token;
	}

	@SuppressWarnings("unchecked")
	private void parse(Element grammar) {
		List<Element> tokenNodes = grammar.getChildren(TOKEN);
		if (tokenNodes != null) {
			for (Element tokenNode : tokenNodes) {
				Token token = parseToken(tokenNode);
			}
		}
	}

	public Tokens parse(String projectPath) {
		SAXBuilder builder = new SAXBuilder();
		try {
			Document document = builder.build(new File(projectPath));
			Element grammar = document.getRootElement();
			parse(grammar);
			return this.tokens;
		} catch (JDOMException myJDOMException) {
			myJDOMException.printStackTrace();
		} catch (IOException myIOException) {
			myIOException.printStackTrace();
		}
		return null;
	}
}
